#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Python+LVGL项目打包脚本
用于生成独立的exe文件

使用方法:
python build_exe.py
"""

import os
import sys
import subprocess
import shutil
from pathlib import Path

class ExeBuilder:
    """EXE构建器"""
    
    def __init__(self):
        self.project_dir = Path(__file__).parent
        self.main_script = self.project_dir / "main.py"
        self.dist_dir = self.project_dir / "dist"
        self.build_dir = self.project_dir / "build"
        self.spec_file = self.project_dir / "main.spec"
        
    def check_dependencies(self):
        """检查依赖"""
        print("🔍 检查依赖环境...")
        
        # 检查Python版本
        python_version = sys.version_info
        if python_version < (3, 7):
            print("❌ 需要Python 3.7+")
            return False
        print(f"✅ Python {python_version.major}.{python_version.minor}.{python_version.micro}")
        
        # 检查PyInstaller
        try:
            import PyInstaller
            print(f"✅ PyInstaller {PyInstaller.__version__}")
        except ImportError:
            print("❌ 请安装PyInstaller: pip install pyinstaller")
            return False
        
        # 检查主要依赖
        missing_deps = []
        deps_to_check = {
            'lvgl': 'LVGL Python绑定',
            'pygame': 'SDL2/Pygame',
        }
        
        for dep, desc in deps_to_check.items():
            try:
                __import__(dep)
                print(f"✅ {desc}")
            except ImportError:
                missing_deps.append(dep)
                print(f"⚠️  {desc} 未安装")
        
        if missing_deps:
            print(f"💡 安装缺失依赖: pip install {' '.join(missing_deps)}")
        
        return True
    
    def clean_previous_builds(self):
        """清理之前的构建"""
        print("🧹 清理之前的构建...")
        
        for dir_to_clean in [self.dist_dir, self.build_dir]:
            if dir_to_clean.exists():
                shutil.rmtree(dir_to_clean)
                print(f"   删除 {dir_to_clean}")
        
        if self.spec_file.exists():
            self.spec_file.unlink()
            print(f"   删除 {self.spec_file}")
    
    def create_spec_file(self):
        """创建PyInstaller spec文件"""
        print("📝 创建PyInstaller配置...")
        
        spec_content = f'''# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(
    ['{self.main_script.as_posix()}'],
    pathex=['{self.project_dir.as_posix()}'],
    binaries=[],
    datas=[
        # 添加LVGL数据文件
        # ('path/to/lvgl/data', 'lvgl/data'),
    ],
    hiddenimports=[
        'lvgl',
        'pygame',
        'threading',
        'time',
        'math',
        'random',
        'dataclasses',
        'typing',
    ],
    hookspath=[],
    hooksconfig={{}},
    runtime_hooks=[],
    excludes=[
        'tkinter',
        'matplotlib',
        'scipy',
        'pandas',
    ],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='LVGLDashboard',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=False,  # 设置为False隐藏控制台窗口
    disable_windowed_traceback=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
    icon=None,  # 可以添加图标文件路径
    version_info={{
        'FileDescription': 'Python+LVGL汽车仪表盘',
        'ProductName': 'LVGL Dashboard',
        'FileVersion': '1.0.0.0',
        'ProductVersion': '1.0.0',
        'CompanyName': '嵌入式开发学习',
        'LegalCopyright': '© 2024',
    }}
)
'''
        
        with open(self.spec_file, 'w', encoding='utf-8') as f:
            f.write(spec_content)
        
        print(f"✅ 创建配置文件: {self.spec_file}")
    
    def build_exe(self):
        """构建EXE文件"""
        print("🔨 开始构建EXE文件...")
        
        # PyInstaller命令
        cmd = [
            sys.executable, '-m', 'PyInstaller',
            '--clean',
            '--noconfirm',
            str(self.spec_file)
        ]
        
        print(f"执行命令: {' '.join(cmd)}")
        
        try:
            result = subprocess.run(
                cmd,
                cwd=self.project_dir,
                capture_output=True,
                text=True,
                encoding='utf-8'
            )
            
            if result.returncode == 0:
                print("✅ 构建成功!")
                
                # 查找生成的exe文件
                exe_file = self.dist_dir / "LVGLDashboard.exe"
                if exe_file.exists():
                    size_mb = exe_file.stat().st_size / (1024 * 1024)
                    print(f"📦 生成文件: {exe_file}")
                    print(f"📏 文件大小: {size_mb:.1f} MB")
                    return True
                else:
                    print("❌ 未找到生成的exe文件")
                    return False
            else:
                print("❌ 构建失败:")
                print("STDOUT:", result.stdout)
                print("STDERR:", result.stderr)
                return False
                
        except Exception as e:
            print(f"❌ 构建过程出错: {e}")
            return False
    
    def create_simple_fallback(self):
        """创建简化版本（当LVGL不可用时）"""
        print("🔄 创建简化版本...")
        
        simple_main = self.project_dir / "simple_main.py"
        
        simple_content = '''#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
简化版Python图形界面
使用tkinter替代LVGL，确保在任何Windows系统上都能运行
"""

import tkinter as tk
from tkinter import ttk
import time
import threading
import random
import math

class SimpleDashboard:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("🚗 Python汽车仪表盘 (简化版)")
        self.root.geometry("800x600")
        self.root.resizable(False, False)
        self.root.configure(bg='#1a1a2e')
        
        # 数据
        self.current_speed = 0
        self.target_speed = 60
        self.current_rpm = 800
        self.fuel_level = 85
        self.running = True
        
        self.create_ui()
        self.start_update_thread()
    
    def create_ui(self):
        """创建界面"""
        # 标题
        title = tk.Label(
            self.root,
            text="🚗 Python汽车仪表盘",
            font=("Arial", 20, "bold"),
            bg='#1a1a2e',
            fg='white'
        )
        title.pack(pady=20)
        
        # 主要数据显示
        main_frame = tk.Frame(self.root, bg='#1a1a2e')
        main_frame.pack(expand=True)
        
        # 速度显示
        self.speed_var = tk.StringVar(value="0")
        speed_frame = tk.Frame(main_frame, bg='#16213e', relief='raised', bd=2)
        speed_frame.pack(side='left', padx=20, pady=20, ipadx=20, ipady=20)
        
        tk.Label(speed_frame, text="速度", font=("Arial", 16), bg='#16213e', fg='#888').pack()
        speed_label = tk.Label(
            speed_frame,
            textvariable=self.speed_var,
            font=("Arial", 48, "bold"),
            bg='#16213e',
            fg='#00ff00'
        )
        speed_label.pack()
        tk.Label(speed_frame, text="km/h", font=("Arial", 12), bg='#16213e', fg='#888').pack()
        
        # 转速显示
        self.rpm_var = tk.StringVar(value="800")
        rpm_frame = tk.Frame(main_frame, bg='#16213e', relief='raised', bd=2)
        rpm_frame.pack(side='left', padx=20, pady=20, ipadx=20, ipady=20)
        
        tk.Label(rpm_frame, text="转速", font=("Arial", 16), bg='#16213e', fg='#888').pack()
        rpm_label = tk.Label(
            rpm_frame,
            textvariable=self.rpm_var,
            font=("Arial", 32, "bold"),
            bg='#16213e',
            fg='#ff8000'
        )
        rpm_label.pack()
        tk.Label(rpm_frame, text="RPM", font=("Arial", 12), bg='#16213e', fg='#888').pack()
        
        # 状态信息
        status_frame = tk.Frame(self.root, bg='#1a1a2e')
        status_frame.pack(pady=20)
        
        self.status_var = tk.StringVar(value="状态: 正常")
        status_label = tk.Label(
            status_frame,
            textvariable=self.status_var,
            font=("Arial", 14),
            bg='#1a1a2e',
            fg='white'
        )
        status_label.pack()
        
        # 燃油进度条
        fuel_frame = tk.Frame(status_frame, bg='#1a1a2e')
        fuel_frame.pack(pady=10)
        
        tk.Label(fuel_frame, text="燃油:", bg='#1a1a2e', fg='white').pack(side='left')
        self.fuel_progress = ttk.Progressbar(
            fuel_frame,
            length=200,
            mode='determinate',
            maximum=100,
            value=85
        )
        self.fuel_progress.pack(side='left', padx=10)
        
        # 控制按钮
        button_frame = tk.Frame(self.root, bg='#1a1a2e')
        button_frame.pack(pady=20)
        
        tk.Button(
            button_frame,
            text="加速",
            command=self.accelerate,
            bg='#00ff00',
            fg='black',
            font=("Arial", 12, "bold"),
            width=10
        ).pack(side='left', padx=10)
        
        tk.Button(
            button_frame,
            text="减速",
            command=self.decelerate,
            bg='#ff0000',
            fg='white',
            font=("Arial", 12, "bold"),
            width=10
        ).pack(side='left', padx=10)
        
        tk.Button(
            button_frame,
            text="随机",
            command=self.random_speed,
            bg='#0080ff',
            fg='white',
            font=("Arial", 12, "bold"),
            width=10
        ).pack(side='left', padx=10)
    
    def accelerate(self):
        """加速"""
        self.target_speed = min(220, self.target_speed + 20)
    
    def decelerate(self):
        """减速"""
        self.target_speed = max(0, self.target_speed - 20)
    
    def random_speed(self):
        """随机速度"""
        self.target_speed = random.randint(0, 220)
    
    def update_data(self):
        """更新数据"""
        # 平滑速度变化
        if self.current_speed < self.target_speed:
            self.current_speed = min(self.current_speed + 2, self.target_speed)
        elif self.current_speed > self.target_speed:
            self.current_speed = max(self.current_speed - 2, self.target_speed)
        
        # 计算转速
        self.current_rpm = 800 + (self.current_speed * 25)
        if self.current_rpm > 7000:
            self.current_rpm = 7000
        
        # 模拟燃油消耗
        if self.current_speed > 0:
            self.fuel_level -= 0.01
            if self.fuel_level < 0:
                self.fuel_level = 0
    
    def update_ui(self):
        """更新界面"""
        self.speed_var.set(str(int(self.current_speed)))
        self.rpm_var.set(str(int(self.current_rpm)))
        self.fuel_progress['value'] = self.fuel_level
        
        if self.current_speed > 100:
            status = "状态: 高速行驶"
        elif self.current_speed > 50:
            status = "状态: 正常行驶"
        elif self.current_speed > 0:
            status = "状态: 低速行驶"
        else:
            status = "状态: 停车"
        
        self.status_var.set(f"{status} | 目标: {int(self.target_speed)} km/h | 燃油: {self.fuel_level:.1f}%")
    
    def start_update_thread(self):
        """启动更新线程"""
        def update_loop():
            while self.running:
                try:
                    self.update_data()
                    self.root.after(0, self.update_ui)
                    time.sleep(0.05)
                except:
                    break
        
        update_thread = threading.Thread(target=update_loop, daemon=True)
        update_thread.start()
    
    def run(self):
        """运行应用"""
        try:
            self.root.mainloop()
        except KeyboardInterrupt:
            pass
        finally:
            self.running = False

def main():
    """主函数"""
    app = SimpleDashboard()
    app.run()

if __name__ == "__main__":
    main()
'''
        
        with open(simple_main, 'w', encoding='utf-8') as f:
            f.write(simple_content)
        
        print(f"✅ 创建简化版本: {simple_main}")
        
        # 构建简化版本的exe
        cmd = [
            sys.executable, '-m', 'PyInstaller',
            '--onefile',
            '--windowed',
            '--name', 'SimpleDashboard',
            '--clean',
            '--noconfirm',
            str(simple_main)
        ]
        
        try:
            result = subprocess.run(cmd, cwd=self.project_dir, capture_output=True, text=True)
            if result.returncode == 0:
                exe_file = self.dist_dir / "SimpleDashboard.exe"
                if exe_file.exists():
                    print(f"✅ 简化版本构建成功: {exe_file}")
                    return True
        except Exception as e:
            print(f"❌ 简化版本构建失败: {e}")
        
        return False
    
    def run(self):
        """运行构建过程"""
        print("🚀 开始构建Python+LVGL应用...")
        
        # 检查依赖
        if not self.check_dependencies():
            return False
        
        # 清理之前的构建
        self.clean_previous_builds()
        
        # 尝试构建完整版本
        self.create_spec_file()
        if self.build_exe():
            print("🎉 完整版本构建成功!")
        else:
            print("⚠️  完整版本构建失败，创建简化版本...")
            if self.create_simple_fallback():
                print("🎉 简化版本构建成功!")
            else:
                print("❌ 所有构建尝试都失败了")
                return False
        
        print("\n📋 构建完成总结:")
        print(f"   构建目录: {self.dist_dir}")
        if self.dist_dir.exists():
            for exe_file in self.dist_dir.glob("*.exe"):
                size_mb = exe_file.stat().st_size / (1024 * 1024)
                print(f"   📦 {exe_file.name} ({size_mb:.1f} MB)")
        
        print("\n💡 使用说明:")
        print("   双击exe文件即可运行")
        print("   如果缺少依赖，会自动使用简化版本")
        
        return True

def main():
    """主函数"""
    builder = ExeBuilder()
    success = builder.run()
    
    if not success:
        print("\n❌ 构建失败")
        input("按Enter键退出...")
        return 1
    else:
        print("\n✅ 构建成功")
        input("按Enter键退出...")
        return 0

if __name__ == "__main__":
    sys.exit(main())